//#ifndef __tenacitas_time__criteria__h__
//#define __tenacitas_time__criteria__h__


///** @file <FILE-DESCRIPTION> */

//// -----------------------------------------------------------------------------
////                                   C++ headers
//// -----------------------------------------------------------------------------
//#include <list>
//#include <algorithm>

//// -----------------------------------------------------------------------------
////                                   3rds headers
//// -----------------------------------------------------------------------------

//// -----------------------------------------------------------------------------
////                                   our headers
//// -----------------------------------------------------------------------------
//#include <tenacitas.number/constant.h>
//#include <tenacitas.number/fault.h>
//#include <tenacitas.number/ints.h>
//#include <tenacitas.memory/ptr.h>

//#include "algorithm.h"

//// -----------------------------------------------------------------------------
////                                   namespaces
//// -----------------------------------------------------------------------------
//using namespace std;
//using namespace tenacitas;

//// -----------------------------------------------------------------------------
////                                   macro constants
//// -----------------------------------------------------------------------------

///** @def <MACRO-CONTANT-NAME> */
///**

//// -----------------------------------------------------------------------------
////                                   macro commands
//// -----------------------------------------------------------------------------

///** @def <MACRO-COMMAND-NAME> */
///** */

//// -----------------------------------------------------------------------------
////                                   typedefs
//// -----------------------------------------------------------------------------

///** @typedef */
///** */



///** namespace of the organization */
//namespace tenacitas {

//    // ---------------------------------------------------------------------
//    //                           pre-declarations
//    // ---------------------------------------------------------------------



//    // ---------------------------------------------------------------------
//    //                          typedefs
//    // ---------------------------------------------------------------------

//    /** @typedef */
//    /** */
	

//    // ---------------------------------------------------------------------
//    //                          declarations
//    // ---------------------------------------------------------------------


//    /** recurrence_criteria
//     * Defines criteria for a type of time to be inserted in a
//     * sequence created by a time recurrence pattern.
//     *
//     * @note Please, read the tenacitas::recurrence for a full
//     * documentation on time recurrence.
//     *
//     * The @p t_time type parameter defines the type of time, for
//     * example tenacitas::date.
//     *
//     * The @p t_period type parameter defines the type of period, for example,
//     * tenacitas::date::day, tenacitas::date::month, tenacitas::date::year and
//     * tenacitas::date::weekday */
//    template <typename t_time, typename t_period>
//    class recurrence_criteria {

//	// -----------------------------------------------------------------
//	/** @name               friends */
//	// -----------------------------------------------------------------
	    
//	/* @{ */

//	/* @} */


//    public:
//	// -----------------------------------------------------------------
//	// recurrence_criteria  public internal types
//	// -----------------------------------------------------------------

//	/** Type for the type of time */
//	typedef t_time time_type;

//	/** Type for the type of period */
//	typedef t_period period_type;

//	/** Type for the actual type of criteria used */
//	typedef recurrence_criteria<time_type, period_type> criteria_type;

//	/** Type for values that define what to do in case a
//         * calculated @p time_type object falls on a holiday, weekend or a
//         * exception list
//         */
//	typedef tenacitas::constant<u8t, criteria_type> creation_policy;
	    

//	// -----------------------------------------------------------------
//	// recurrence_criteria  public constructors
//	// -----------------------------------------------------------------

//	/** Constructor
//         *
//         * @param [in] p_on_holidays is a object that informs if a
//         * certain date is a holiday. This class must provide the method
//         * <tt> static bool find ( const t_time::day_value &
//         * time_as_value ) </tt>, which should return @p true if a certain
//         * @p t_time, in its raw numeric format, is a holiday
//         *
//         * @param p_on_weekends [in] defines what should be done if a
//         * calculated @p time_type object falls on a weekend
//         *
//         * @param p_on_exceptions [in] defines what should be done if a
//         * calculated @p time_type object is listed in a exception list,
//         * which enumerates the @p time_type objects that should be avoided
//         *
//         * @param p_on_invalide_times [in] defines what should be done if a
//         * calculated @p time_type object is invalid, like 2009.02.30
//         *
//         * @param p_holidays is a list of dates that are holidays
//         *
//         * @note The possible values for @p on_holidays, @p on_weekends and
//         * @p on_exceptions are
//         * tenacitas::recurrence_criteria::create_before,
//         * tenacitas::recurrence_criteria::dont_create,
//         * tenacitas::recurrence_criteria::create_after,
//         * tenacitas::recurrence_criteria::create_anyway
//         *
//         * @note If the parameter @p on_invalid_times is set to @p
//         * create_anyway, a tenacitas::fault will be generated
//         */
//	recurrence_criteria ( const creation_policy & p_on_holidays,
				  
//			      const creation_policy & p_on_weekends,
				  
//			      const creation_policy & p_on_exceptions,
				  
//			      const creation_policy & p_on_invalid_times,
				  
//			      const list<typename t_time::date_type> &
//			      p_holidays )

//	    throw ( fault ) ;

//	/** Destructor */
//	virtual ~recurrence_criteria( ) ;
	    

//	// -----------------------------------------------------------------
//	// recurrence_criteria  public processors
//	// -----------------------------------------------------------------

//	/** Returns the first time of the sequence, based
//         * on a @p time_type object
//         *
//         * @param [in] t is a  @p time_type object used to calculate the first
//         * @p time_type.
//         * Examples:
//         * - if the criteria is: mondays and wednesdays, and @p t is
//         * 2009.03.03, this method should return 2009.03.02.
//         *
//         * - if the criteria is: days 13, 17, 20, and @p t is 2009.03.03,
//         * this method should return 2009.03.13 */
//	virtual time_type first_time ( const time_type & p_time ) const = 0;

//	/** Calculates the next valid time for a given time
//         *
//         * @param [in] previous is the previous t_time to which we
//         * want to calculate the next valid t_time
//         *
//         * @param [in] except_on is a list of @p time_type objects that
//         * should conform to the @p on_exceptions parameter passed to the
//         * constructor, i.e., if @p on_exceptions is @p create_before, then
//         * if @p next_time calculates a @p time_type object that is listed
//         * in @p except_on, then @p next_time should calculate a @p
//         * time_type object previous to that @p time_type first calculated
//         *
//         * @param [in] next is the calculate @p time_type object
//         *
//         * @return @p true if it was possible to calculate a next @p time_type
//         * objcet, @p false otherwise */
//	bool next_time ( const time_type & p_previous,
//			 const list<time_type> & p_except_on,
//			 time_type & p_next ) const;
	    


//	// -----------------------------------------------------------------
//	// recurrence_criteria  public attributes
//	// -----------------------------------------------------------------


//	/** Defines that if a calculated @p time_type object is
//         * either a holiday, a weekend or a exception, another @p time_type
//         * object immediately before this must be calculated */
//	static const creation_policy create_before;

//	/** Defines that if a calculated @p time_type object is
//         * either a holiday, a weekend or a exception, no @p time_type
//         * object must be created */
//	static const creation_policy dont_create;

//	/** Defines that if a calculated @p time_type object is
//         * either a holiday, a weekend or a exception, another @p time_type
//         * object immediately after this must be calculated */
//	static const creation_policy create_after;

//	/** Defines that even if a calculated @p time_type object is
//         * either a holiday, a weekend or a exception, it should be used
//         * anyway
//         * @note If the parameter @p on_invalid_times of the constructor is
//         * set to @p create_anyway, a tenacitas::fault will be
//         * generated  */
//	static const creation_policy create_anyway;

//	/** Code of the exception thrown if the parameter @p
//         * on_invalid_times of the constructor is set to @p create_anyway */
//	static const fault::code create_anyway_on_invalid_date;

	    
//    protected:

//	// -----------------------------------------------------------------
//	// recurrence_criteria  protected processors
//	// -----------------------------------------------------------------

//	/** Method specialized in calculating the next @p t_time
//         * after a previous one
//         *
//         * @param [in] previous is the previous @p t_time object
//         *
//         * @param [out] next is the (possibly) next @p t_time object
//         *
//         * @return @p true if it was possible to calculate @p next
//         *         @p false, otherwise */
//	virtual bool next ( const time_type & p_previous,
//			    time_type & p_time ) const throw ( fault )  = 0;

//	/** Decides, based on the parameter @p on_invalid_times informed
//         * in the constructor, what to do if @p next calculates an invalid next
//         * time_type
//         *
//         * @param [in] p_original is the time from where we wanted to calculate
//         * a next time_type
//         *
//         * @param [in] p_offending_day is the time_type::day_type that
//         * generated an invalid time_type
//         *
//         * @param [in-out] p_new_time is the new time_type calculated, if
//         * possible
//         *
//         * @return @p true if it was possible to calculate  @p p_new_time, @p
//         * false otherwise */
//	bool handle_invalid_time ( const t_time & p_original,
//				   const typename t_time::day_type &
//				   p_offending_day,
//				   t_time & p_new_time ) const;
	    

//	// -----------------------------------------------------------------
//	// recurrence_criteria  protected operators
//	// -----------------------------------------------------------------

//	// -----------------------------------------------------------------
//	// recurrence_criteria  protected attributes
//	// -----------------------------------------------------------------

//    private:

//	// -----------------------------------------------------------------
//	// recurrence_criteria  private processors
//	// -----------------------------------------------------------------

//	/** Informs if a @p t_time object is in the exceptions
//         * list of @p t_time objects
//         *
//         * @param [in] p_time is the @p t_time that we want to find out if
//         * it is in the exceptions list
//         *
//         * @param [in] p_except_on is the list of @p t_time that, at
//         * first, should not be used
//         *
//         * @return @p true if it is in the exception list
//         *         @p false otherwise */
//	bool is_exception ( const time_type & p_time,
//			    const list<t_time> & p_except_on ) const;

//	/** Informs if a @p t_time is a holiday
//         *
//         * @param [in] p_time is the @p t_time that we want to find out if
//         * it is a holiday
//         *
//         * @return @p true if it is a holiday
//         *         @p false otherwise */
//	bool is_holiday ( const time_type & p_time ) const ;

//	/** Validates a @p t_time object, trying to create
//         * another one, if necessary, according to the
//         * tenacitas::recurrence_critertia::creation_policy
//         * attributes, defined in the constructor
//         *
//         * @param [in] p_except_on is the list of @p t_time that, at
//         * first, should not be used
//         *
//         * @param [out] p_time is the @p t_time_time object to be validate,
//         * and, if necessary, modified according to the
//         * tenacitas::recurrence_critertia::creation_policy
//         * attributes, defined in the constructor */
//	bool validate_time ( const list<t_time> & p_except_on,
//			     t_time & p_time) const;
	    

//	/** Apply a policy defined in the constructor
//         *
//         * Depending on the value policy, this method tries to create a day
//         * after or before @p p_time. In these cases, the new possible @p
//         * time_type is validate again, through the method @p
//         * validate_time
//         *
//         * @param [in] p_policy is a @p creation_policy object to be analised
//         *
//         * @param [in] p_except_on is the list of @p t_time that, at
//         * first, should not be used
//         *
//         * @param [in] p_time is the @p t_time on which the policy will
//         * be evaluated */
//	bool evaluate_policy ( const creation_policy & p_policy,
//			       const list<t_time> & p_except_on,
//			       t_time & p_time) const;
	    

//	// -----------------------------------------------------------------
//	// recurrence_criteria  private operators
//	// -----------------------------------------------------------------

//	// -----------------------------------------------------------------
//	// recurrence_criteria  private attributes
//	// -----------------------------------------------------------------

//	const creation_policy m_on_holidays ;
//	const creation_policy m_on_weekends ;
//	const creation_policy m_on_exceptions ;
//	const creation_policy m_on_invalid_times ;

//	list<typename t_time::date_type> m_holidays;
//    };

//    // ==================================================
//    //                IMPLEMENTATION
//    // ==================================================

//    template <typename t_time, typename t_period>
//    const typename recurrence_criteria<t_time, t_period>::creation_policy
//    recurrence_criteria<t_time, t_period>::dont_create ( 1 );

//    template <typename t_time, typename t_period>
//    const typename recurrence_criteria<t_time, t_period>::creation_policy
//    recurrence_criteria<t_time, t_period>::create_after ( 2 );

//    template <typename t_time, typename t_period>
//    const typename recurrence_criteria<t_time, t_period>::creation_policy
//    recurrence_criteria<t_time, t_period>::create_before ( 3 );

//    template <typename t_time, typename t_period>
//    const typename recurrence_criteria<t_time, t_period>::creation_policy
//    recurrence_criteria<t_time, t_period>::create_anyway ( 4 ) ;


//    template <typename t_time, typename t_period>
//    const fault::code
//    recurrence_criteria<t_time, t_period>::create_anyway_on_invalid_date ( 5 ) ;

	

//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    recurrence_criteria<t_time, t_period>::
//    recurrence_criteria ( const creation_policy & p_on_holidays,
//			  const creation_policy & p_on_weekends,
//			  const creation_policy & p_on_exceptions,
//			  const creation_policy & p_on_invalid_times,
//			  const list<typename t_time::date_type> &
//			  p_holidays)
//	throw ( fault ) :
	    

//	m_on_holidays ( p_on_holidays ) ,
//	m_on_weekends ( p_on_weekends ) ,
//	m_on_exceptions ( p_on_exceptions ),
//	m_on_invalid_times ( p_on_invalid_times ),
//	m_holidays ( p_holidays ) {

//	if ( m_on_invalid_times == create_anyway ) {
//	    throw ( create_fault ( recurrence_criteria<t_time>,
//				   create_anyway_on_invalid_date) );
//	}
	    
//    }
	
//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    recurrence_criteria<t_time, t_period>::
//    ~recurrence_criteria ( ) {}
	

//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    bool
//    recurrence_criteria<t_time, t_period>::
//    next_time ( const t_time & p_previous,
//		const list<t_time> & p_except_on,
//		t_time & p_time ) const {

//	bool rc = false;
//	try {
//	    // calculates the next time to 'p_time' from 'p_previous'
//	    rc = next ( p_previous, p_time );

//	    if ( rc ) {
//		// validates the calculated time 'p_time'
//		rc = validate_time ( p_except_on, p_time ) ;
//	    }
//	}
//	catch ( fault f ) {
//	    rc = false;
//	}
	    
//	return rc;
//    }

//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    bool
//    recurrence_criteria<t_time, t_period>::
//    handle_invalid_time ( const t_time & p_original,
//			  const typename t_time::day_type & p_offending_day,
//			  t_time & p_new_time ) const {

//	bool rc = false;
	    
//	// ok, the cadidate day, together with the month and
//	// year produced a invalid time, like 2009.04.31

//	// so, what should we do if an ivalid time is
//	// calculated?

//	// should we try to create a time before this
//	// invalid one?
//	if ( m_on_invalid_times == create_before) {
//	    typename t_time::day_type d =
//		round_day ( p_offending_day,
//			    p_original.get_month( ) ,
//			    p_original.get_year( ) ) ;
//	    p_new_time = p_original;
//	    p_new_time.set_day ( d ) ;
				
//	    rc = true;
				
//	}
//	// or should we try to create after?
//	else if ( m_on_invalid_times == create_after) {
//	    // if so, we shift the month forward, as an invalid date means a day
//	    // that does not exist in the month, like june, 31th
//	    shift<typename t_time::month_type, t_time> sm;
//	    p_new_time = sm ( p_original, 1 ) ;

//	    // and set the day as the first of the next month
//	    p_new_time.set_day ( 1 ) ;
//	    rc = true;
//	}
//	// or we should do nothing?
//	else if ( m_on_invalid_times == dont_create) {
//	    rc = false;
//	}
                
//	return rc;
//    }
	
//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    bool
//    recurrence_criteria<t_time, t_period>::
//    validate_time ( const list<t_time> & p_except_on,
//		    t_time & p_time ) const {
//	bool rc = false;

//	try {

//	    // ok, it is a valid time, but...

//	    // is it an exception time?
//	    if ( is_exception ( p_time, p_except_on ) ) {
//		rc = evaluate_policy ( m_on_exceptions, p_except_on, p_time ) ;
//	    }
//	    // is it a holiday?
//	    else if ( is_holiday ( p_time ) ) {
//		rc = evaluate_policy ( m_on_holidays, p_except_on, p_time ) ;
//	    }
//	    // is it a weekend?
//	    else if ( is_weekend ( p_time ) ) {
//		rc = evaluate_policy ( m_on_weekends, p_except_on, p_time ) ;
//	    }
//	    else {
//		// no, so it is a valid time!
//		rc = true;
//	    }
//	}
//	catch ( fault f ) {
//	    rc = false;
//	}
	    
//	return rc;
//    }
	

//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    bool
//    recurrence_criteria<t_time, t_period>::
//    evaluate_policy ( const creation_policy & p_policy,
//		      const list<t_time> & p_except_on,
//		      t_time & p_time ) const {

//	bool rc = false;
	    
//	// what is the policy?

//	if ( p_policy == dont_create ) {
//	    // set @p t with a default t_time
//	    p_time = t_time ( ) ;
//	    // and flag that it was not possible to validate the time
//	    rc = false;
//	} else if ( p_policy == create_after ) {

//	    // moving one day forward
//	    shift<typename t_time::day_type, t_time> sd;
//	    t_time new_t = sd ( p_time, 1 ) ;

//	    // and try to validate this new time
//	    rc = validate_time ( p_except_on, p_time ) ;
//	} else if ( p_policy == create_before ) {
//	    // moving one day backward
//	    shift<typename t_time::day_type, t_time> sd;
//	    t_time new_t = sd ( p_time, -1 ) ;

//	    // and try to validate this new time
//	    rc = validate_time ( p_except_on, p_time ) ;
//	} else if ( p_policy == create_anyway ) {
//	    rc = true;
//	}
	    
//	return rc;
//    }


//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    bool
//    recurrence_criteria<t_time, t_period>::
//    is_exception ( const time_type & p_time,
//		   const list<t_time> & p_except_on ) const {
//	return ( std::find ( p_except_on.begin( ),
//			     p_except_on.begin( ),
//			     p_time ) != p_except_on.end( ) ) ;
//    }
	
	    
//    // ---------------------------------------------------------------------
//    template <typename t_time, typename t_period>
//    bool
//    recurrence_criteria<t_time, t_period>::
//    is_holiday ( const time_type & p_time ) const {
//	return ( std::find ( m_holidays.begin( ), m_holidays.end( ), p_time )
//		 !=  m_holidays.end( ) ) ;
//    }


//} // namespace tenacitas


//#endif

